#pragma once
#include "basic_component/common.hpp"
#include "basic_component/Socket.hpp"
#include "Epoll.hpp"
#include "Connection.hpp"
#include <unordered_map>


class reactor_server
{
private:
    bool connection_is_exist_helper(int sockfd) const
    {
        auto it = _connections.find(sockfd);
        if(it == _connections.end())
            return false;

        return true;
        
    }



    bool erase_connection_helper(int sockfd)
    {
        //1. 判断连接是否存在
        if(connection_is_exist(sockfd) == false)
        {
            LOG(wzx::log_level::INFO) << "Connection: " << sockfd << " does not exist, reactor_server erase fail !!!";
            return false;
        }

        //2. 从epoll模型中删除
        _epoll_ptr->erase(sockfd);

        //3. 从连接管理器中删除
        _connections.erase(sockfd);

        //4. 关闭fd -- 可关可不管, 因为connection对象底层的sockfd是智能指针托管的
        close(sockfd);

        LOG(wzx::log_level::INFO) << "Connection: " << sockfd << " erase success ~~~";
        return true;
    }



    //事件派发器
    void event_dispatcher(const struct epoll_event* event_arr, int ready_fd_count)
    {
        for(int i = 0; i < ready_fd_count; ++i)
        {
            int sockfd = event_arr[i].data.fd;
            int revents = event_arr[i].events;
            //判断连接是否存在 -- 增强鲁棒性
            if(connection_is_exist(sockfd))
            {
                //1. 将所有的异常处理, 统一转化成IO错误;  2. 将所有的IO错误, 统一转换成为一个异常处理函数
                if(revents & EPOLLERR/*对应的fd发生错误*/ || revents & EPOLLHUP/*对应的fd被挂断*/)
                    revents |= (EPOLLIN & EPOLLOUT); //1. 将所有的异常处理, 统一转化成IO错误

                if(revents & EPOLLIN)//读事件就绪
                    _connections[sockfd]->receive();//不用区分是listen_fd还是IO_fd -- 多态

                //不用else if, 以防该fd会同时处理读写(情况很少)
                if(revents & EPOLLIN)//写事件就绪
                    _connections[sockfd]->send();

            }
        }
    }



public:
    reactor_server()
        :_epoll_ptr(std::make_unique<epoll>())
        ,_running_tag(false)
    {}



    bool connection_is_exist(int sockfd) const
    {
        return connection_is_exist_helper(sockfd);
    }
    bool connection_is_exist(const std::shared_ptr<connection>& con_ptr) const
    {
        return connection_is_exist_helper(con_ptr->get_sockfd());
    }

    

    bool insert_connection(std::shared_ptr<connection>& con_ptr)
    {
        //1. 判定是否重复添加
        if(connection_is_exist(con_ptr) == true)
        {
            LOG(wzx::log_level::INFO) << "insert connection: " << con_ptr->get_sockfd() << " repetitively, reactor_server insert fail !!!";
            return false;
        }

        //2. 添加进epoll模型 -- 写透到内核
        _epoll_ptr->insert(con_ptr->get_sockfd(), con_ptr->get_events());
            
        //3. 设置连接的回指指针
        con_ptr->set_server(this);

        //4. 添加进连接管理器
        _connections[con_ptr->get_sockfd()] = con_ptr;

        LOG(wzx::log_level::INFO) << "Connection: " << con_ptr->get_sockfd() << " insert success ~~~";
        return true;
    }



    bool erase_connection(int sockfd)
    {
        return erase_connection_helper(sockfd);
    }
    bool erase_connection(std::shared_ptr<connection>& con_ptr)
    {
        return erase_connection_helper(con_ptr->get_sockfd());
    }


    bool change_connection_events_IN_and_OUT(int sockfd, bool events_IN, bool events_OUT)
    {
        //1. 判断连接是否存在
        if(connection_is_exist(sockfd) == false)
        {
            LOG(wzx::log_level::INFO) << "Connection: " << sockfd << " does not exist, reactor_server erase fail !!!";
            return false;
        }

        //2. 设置连接属性
        uint32_t new_events = EPOLLET | (events_IN ? EPOLLIN : 0) | (events_OUT ? EPOLLOUT : 0);
        _connections[sockfd]->set_events(new_events);
        
        //3. 修改epoll模型内的节点 -- 写透进内核
        _epoll_ptr->change(sockfd, new_events);

        return true;
    }
    

    void start()
    {
        //1. 判断当前server里有无连接
        if(_connections.empty())
        {
            LOG(wzx::log_level::INFO) << "There is no connection within the server :(";   
            return;
        }

        LOG(wzx::log_level::INFO) << "server start...";
        _running_tag = true;
        while(_running_tag)
        {
            //2. 获取已就绪的事件
            struct epoll_event* event_arr;
            int ready_fd_count = _epoll_ptr->wait(&event_arr);//这里要传二级指针才能做到输出型参数!!!!!!!!!!

            //3. 事件派发
            event_dispatcher(event_arr, ready_fd_count);//wait返回值为0也没关系, 大不了不派发
        }
    }



private:
    //1. epoll模型
    std::unique_ptr<epoll> _epoll_ptr;
    
    //2. 连接管理器 -- 先描述再组织
    std::unordered_map<int, std::shared_ptr<connection>> _connections;//[多态]: 可同时管理listen_connection和connection

    //3. 运行标识
    bool _running_tag;

    //放在epoll模型里了
    // //4. 用户层数组, 用于接受epoll_wait()返回的已就绪就绪事件. 注: 每次调用 都从_event_arr[0]开始接受
    // std::unique_ptr<struct epoll_event[]> _event_arr;

};